
package org.smile.json;

import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import org.smile.beans.BeanUtils;
import org.smile.exception.JSONParseException;
import org.smile.json.parser.JSONTokener;
import org.smile.util.ClassTypeUtils;
import org.smile.util.ObjectLenUtils;

/**
 * json操作类
 * @author 胡真山
 */
public class JSONValue{
	
	/**
	 * 解析一个字符串为JSON对象
	 * @param jsonStr
	 * @return
	 * @throws JSONParseException
	 */
	public static JSONAware parse(String jsonStr) throws JSONParseException{
		if(jsonStr==null||"".equals(jsonStr)){
			return null;
		}
		JSONTokener tokener=new JSONTokener(jsonStr);
		if (jsonStr.trim().startsWith("[")) {
            return new JSONArray(tokener);
        }else if(jsonStr.trim().startsWith("{")){
        	return new JSONObject(tokener);
        }else{
        	throw new JSONParseException("不规范的JSON格式字符串:must start withd [ or {");
        }
	}
	/**
	 * 转一个obejct成一个json格式
	 * @param value
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String toJSONString(Object value) {
		if (value == null){
			return "null";
		}else if(ClassTypeUtils.isBasicType(value.getClass())){
			if(ObjectLenUtils.hashLength(value)){
				//如果是基础数据类型的数组
				Object[] array=new Object[Array.getLength(value)];
				for(int i=0;i<array.length;i++){
					array[i]=Array.get(value, i);
				}
				return toJSONString(array);
			}else{
				return value.toString();
			}
		}else if (value instanceof String){
			return "\"" + escape((String) value) + "\"";
		}else if (value instanceof Short) {
			return value.toString();
		}else if (value instanceof Double) {
			if (((Double) value).isInfinite() || ((Double) value).isNaN()) {
				return "null";
			} else {
				return value.toString();
			}
		}
		else if (value instanceof Float) {
			if (((Float) value).isInfinite() || ((Float) value).isNaN())
				return "null";
			else
				return value.toString();
		}
		else if (value instanceof Number) {
			return value.toString();
		}
		else if (value instanceof Boolean) {
			return value.toString();
		}
		else if(value instanceof Date){
			DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			return "\""+df.format(value)+ "\"";
		}
		else if (value instanceof Map) {
			return toJSONString((Map) value);
		}
		else if (value instanceof Collection) {
			return JSONArray.toJSONString((Collection) value);
		}
		else if(value instanceof Object[]){
			return JSONArray.toJSONString((Object[])value);
		}
		else {
			try {
				return toJSONString(BeanUtils.mapFromBean(value));
			} catch (Exception e) {
				throw new RuntimeException("JSON化对象失败:"+value.getClass().getName()+"=="+value,e);
			}
		}
	}

	/**
	 * 把一个map转成json格式
	 * @param map
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String toJSONString(Map map){
		if(map == null)
			return "null";
        StringBuffer sb = new StringBuffer();
        boolean first = true;
		Iterator iter=map.keySet().iterator();
        sb.append('{');
		while(iter.hasNext()){
            if(first){
                first = false;
            }
            else{
                sb.append(',');
            }
			sb.append('\"');
			Object key=iter.next();
	        if(key == null){
	            sb.append("null");
	        }
	        else{
	            sb.append(escape(key.toString()));
	        }
			sb.append('\"').append(':');
			
			sb.append(JSONValue.toJSONString(map.get(key)));
		}
        sb.append('}');
		return sb.toString();
	}
	/**
	 * @param 转义字符
	 *           
	 * @param sb
	 */
	static String escape(String s) {
		if (s == null)
			return null;
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < s.length(); i++) {
			char ch = s.charAt(i);
			switch (ch) {
			case '"':
				sb.append("\\\"");
				break;
			case '\\':
				sb.append("\\\\");
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\r':
				sb.append("\\r");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '/':
				sb.append("\\/");
				break;
			default:
				if ((ch >= '\u0000' && ch <= '\u001F')
						|| (ch >= '\u007F' && ch <= '\u009F')
						|| (ch >= '\u2000' && ch <= '\u20FF')) {
					String ss = Integer.toHexString(ch);
					sb.append("\\u");
					for (int k = 0; k < 4 - ss.length(); k++) {
						sb.append('0');
					}
					sb.append(ss.toUpperCase());
				} else {
					sb.append(ch);
				}
			}
		}
		return sb.toString();
	}
	/**
	 *解析时 转换字符串为对象
	 * @param string
	 * @return
	 */
	public static Object stringToValue(String string) {
        Double d;
        if (string.equals("")) {
            return "";
        }
        if (string.equalsIgnoreCase("true")) {
            return Boolean.TRUE;
        }
        if (string.equalsIgnoreCase("false")) {
            return Boolean.FALSE;
        }
        if (string.equalsIgnoreCase("null")) {
            return null;
        }
        char b = string.charAt(0);
        if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
            try {
                if (string.indexOf('.') > -1 ||
                        string.indexOf('e') > -1 || string.indexOf('E') > -1) {
                    d = Double.valueOf(string);
                    if (!d.isInfinite() && !d.isNaN()) {
                        return d;
                    }
                } else {
                    Long myLong = new Long(string);
                    if (myLong.longValue() == myLong.intValue()) {
                        return new Integer(myLong.intValue());
                    } else {
                        return myLong;
                    }
                }
            } catch (Exception ignore) {
            }
        }
        return string;
    }
	/**
	 * 写一个对象以JSON格式到一个writer中
	 * @param bean 源对象
	 * @param writer
	 * @throws IOException
	 */
	public static void write(Object bean,Writer writer) throws IOException{
		try{
			StringReader reader=new StringReader(toJSONString(bean));
			char[] temp=new char[1024];
			while(reader.read(temp)>0){
				writer.write(temp);
			}
		}finally{
			writer.close();
		}
	}
}
